/*-------------------------------------------------------------------------
 *
 * nbtcompare.c
 *	  btree 访问方法的比较函数。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/access/nbtree/nbtcompare.c
 *
 * NOTES
 *
 *	这些函数存储在 pg_amproc 中。对于每个在 btree 上定义的操作类，它们计算
 *
 *				compare(a, b):
 *						< 0 如果 a < b,
 *						= 0 如果 a == b,
 *						> 0 如果 a > b。
 *
 *	结果总是一个 int32，无论输入数据类型是什么。
 *
 *	虽然任何负的 int32 都可以用于报告 "<"，任何正的 int32 都可以用于报告 ">"，但是处理 32 位或更大数据类型的例程不能仅仅返回 "a - b"。
 *	那样可能会溢出而给出错误答案。
 *
 *	注意：对所有非 NULL 值的数据类型，比较函数强制施加一个全序关系是关键，并且数据类型的布尔比较操作符（= < >= 等）必须给出与比较例程一致的结果。
 *	否则可能会导致不良行为。（例如，比较操作符在面对 NAN 或其他奇怪值时必须不跳过；你必须设计一个针对所有此类值的排序序列。）如果数据类型不是微不足道的，这通常最可靠的做法是让布尔操作符调用与 btree 函数相同的三向比较代码。因此，这个文件仅包含对“微不足道”数据类型的 btree 支持——所有其他的都在实现其数据类型的 /utils/adt/ 文件中。
 *
 *	注意：这些例程不能泄露内存，因为在索引访问期间分配的内存直到查询结束时才会被回收。这主要影响可烤焦数据类型的比较例程；它们必须小心释放任何输入数据的去烤焦副本。
 *
 *	注意：我们过去禁止比较函数返回 INT_MIN，但这被证明是太易错的，因为某些平台的 memcmp() 等的版本可以返回 INT_MIN。作为压力测试调用者的手段，可以用定义为 STRESS_SORT_INT_MIN 的编译该文件，导致许多这些函数返回 INT_MIN 或 INT_MAX，而不是它们通常的 -1/+1。不过对于生产环境，这并不是一个好主意，因为用户或第三方代码可能会期望传统的结果。
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <limits.h>

#include "utils/builtins.h"
#include "utils/sortsupport.h"

#ifdef STRESS_SORT_INT_MIN
#define A_LESS_THAN_B		INT_MIN
#define A_GREATER_THAN_B	INT_MAX
#else
#define A_LESS_THAN_B		(-1)
#define A_GREATER_THAN_B	1
#endif


Datum btboolcmp(PG_FUNCTION_ARGS)
{
	bool		fc_a = PG_GETARG_BOOL(0);
	bool		fc_b = PG_GETARG_BOOL(1);

	PG_RETURN_INT32((int32) fc_a - (int32) fc_b);
}

Datum btint2cmp(PG_FUNCTION_ARGS)
{
	int16		fc_a = PG_GETARG_INT16(0);
	int16		fc_b = PG_GETARG_INT16(1);

	PG_RETURN_INT32((int32) fc_a - (int32) fc_b);
}

static int fc_btint2fastcmp(Datum fc_x, Datum fc_y, SortSupport fc_ssup)
{
	int16		fc_a = DatumGetInt16(fc_x);
	int16		fc_b = DatumGetInt16(fc_y);

	return (int) fc_a - (int) fc_b;
}

Datum btint2sortsupport(PG_FUNCTION_ARGS)
{
	SortSupport fc_ssup = (SortSupport) PG_GETARG_POINTER(0);

	fc_ssup->comparator = fc_btint2fastcmp;
	PG_RETURN_VOID();
}

Datum btint4cmp(PG_FUNCTION_ARGS)
{
	int32		fc_a = PG_GETARG_INT32(0);
	int32		fc_b = PG_GETARG_INT32(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

Datum btint4sortsupport(PG_FUNCTION_ARGS)
{
	SortSupport fc_ssup = (SortSupport) PG_GETARG_POINTER(0);

	fc_ssup->comparator = ssup_datum_int32_cmp;
	PG_RETURN_VOID();
}

Datum btint8cmp(PG_FUNCTION_ARGS)
{
	int64		fc_a = PG_GETARG_INT64(0);
	int64		fc_b = PG_GETARG_INT64(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

#if SIZEOF_DATUM < 8
static int btint8fastcmp(Datum x, Datum y, SortSupport ssup)
{
	int64		a = DatumGetInt64(x);
	int64		b = DatumGetInt64(y);

	if (a > b)
		return A_GREATER_THAN_B;
	else if (a == b)
		return 0;
	else
		return A_LESS_THAN_B;
}
#endif

Datum btint8sortsupport(PG_FUNCTION_ARGS)
{
	SortSupport fc_ssup = (SortSupport) PG_GETARG_POINTER(0);

#if SIZEOF_DATUM >= 8
	fc_ssup->comparator = ssup_datum_signed_cmp;
#else
	ssup->comparator = btint8fastcmp;
#endif
	PG_RETURN_VOID();
}

Datum btint48cmp(PG_FUNCTION_ARGS)
{
	int32		fc_a = PG_GETARG_INT32(0);
	int64		fc_b = PG_GETARG_INT64(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

Datum btint84cmp(PG_FUNCTION_ARGS)
{
	int64		fc_a = PG_GETARG_INT64(0);
	int32		fc_b = PG_GETARG_INT32(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

Datum btint24cmp(PG_FUNCTION_ARGS)
{
	int16		fc_a = PG_GETARG_INT16(0);
	int32		fc_b = PG_GETARG_INT32(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

Datum btint42cmp(PG_FUNCTION_ARGS)
{
	int32		fc_a = PG_GETARG_INT32(0);
	int16		fc_b = PG_GETARG_INT16(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

Datum btint28cmp(PG_FUNCTION_ARGS)
{
	int16		fc_a = PG_GETARG_INT16(0);
	int64		fc_b = PG_GETARG_INT64(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

Datum btint82cmp(PG_FUNCTION_ARGS)
{
	int64		fc_a = PG_GETARG_INT64(0);
	int16		fc_b = PG_GETARG_INT16(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

Datum btoidcmp(PG_FUNCTION_ARGS)
{
	Oid			fc_a = PG_GETARG_OID(0);
	Oid			fc_b = PG_GETARG_OID(1);

	if (fc_a > fc_b)
		PG_RETURN_INT32(A_GREATER_THAN_B);
	else if (fc_a == fc_b)
		PG_RETURN_INT32(0);
	else
		PG_RETURN_INT32(A_LESS_THAN_B);
}

static int fc_btoidfastcmp(Datum fc_x, Datum fc_y, SortSupport fc_ssup)
{
	Oid			fc_a = DatumGetObjectId(fc_x);
	Oid			fc_b = DatumGetObjectId(fc_y);

	if (fc_a > fc_b)
		return A_GREATER_THAN_B;
	else if (fc_a == fc_b)
		return 0;
	else
		return A_LESS_THAN_B;
}

Datum btoidsortsupport(PG_FUNCTION_ARGS)
{
	SortSupport fc_ssup = (SortSupport) PG_GETARG_POINTER(0);

	fc_ssup->comparator = fc_btoidfastcmp;
	PG_RETURN_VOID();
}

Datum btoidvectorcmp(PG_FUNCTION_ARGS)
{
	oidvector  *fc_a = (oidvector *) PG_GETARG_POINTER(0);
	oidvector  *fc_b = (oidvector *) PG_GETARG_POINTER(1);
	int			fc_i;

	/* 我们任意选择先按向量长度排序 */
	if (fc_a->dim1 != fc_b->dim1)
		PG_RETURN_INT32(fc_a->dim1 - fc_b->dim1);

	for (fc_i = 0; fc_i < fc_a->dim1; fc_i++)
	{
		if (fc_a->values[fc_i] != fc_b->values[fc_i])
		{
			if (fc_a->values[fc_i] > fc_b->values[fc_i])
				PG_RETURN_INT32(A_GREATER_THAN_B);
			else
				PG_RETURN_INT32(A_LESS_THAN_B);
		}
	}
	PG_RETURN_INT32(0);
}

Datum btcharcmp(PG_FUNCTION_ARGS)
{
	char		fc_a = PG_GETARG_CHAR(0);
	char		fc_b = PG_GETARG_CHAR(1);

	/* 小心将字符比较为无符号 */
	PG_RETURN_INT32((int32) ((uint8) fc_a) - (int32) ((uint8) fc_b));
}
